#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Git Hooks 动态配置系统 - 配置解析器
负责解析和管理配置文件
"""

import os
import yaml  # pyright: ignore[reportMissingModuleSource]
import json
import logging
from typing import Dict, List, Any, Optional, Union
from pathlib import Path
from dataclasses import dataclass, field
from enum import Enum


class LogLevel(Enum):
    """日志级别枚举"""
    DEBUG = "debug"
    INFO = "info"
    WARN = "warn"
    ERROR = "error"


class TaskType(Enum):
    """任务类型枚举"""
    LINT = "lint"
    TEST = "test"
    SECURITY = "security"
    BUILD = "build"
    COMMIT_MSG_VALIDATOR = "commit-msg-validator"
    CUSTOM = "custom"


class ConditionType(Enum):
    """条件类型枚举"""
    FILE_PATTERN = "file_pattern"
    FILE_EXISTS = "file_exists"
    BRANCH_PATTERN = "branch_pattern"
    COMMIT_COUNT = "commit_count"
    TIME_RANGE = "time_range"


@dataclass
class GlobalConfig:
    """全局配置类"""
    enabled: bool = True
    log_level: LogLevel = LogLevel.INFO
    log_file: str = ".git/hooks-controller.log"
    fail_fast: bool = True
    max_parallel_tasks: int = 4


@dataclass
class TaskConfig:
    """任务配置类"""
    name: str
    type: TaskType
    config: Dict[str, Any] = field(default_factory=dict)
    conditions: List[Dict[str, Any]] = field(default_factory=list)
    parallel: bool = False
    timeout: Optional[int] = None
    retry_count: int = 0
    enabled: bool = True


@dataclass
class HookConfig:
    """Hook 配置类"""
    enabled: bool = True
    description: str = ""
    tasks: List[TaskConfig] = field(default_factory=list)


@dataclass
class PluginConfig:
    """插件配置类"""
    name: str
    path: str
    enabled: bool = True
    config: Dict[str, Any] = field(default_factory=dict)


class ConfigParser:
    """配置解析器"""
    
    def __init__(self, config_dir: str = "config"):
        self.config_dir = Path(config_dir)
        self.logger = logging.getLogger(__name__)
        self._config_cache = {}
        
    def load_config(self, config_file: str = "hooks.yaml") -> Dict[str, Any]:
        """加载配置文件"""
        config_path = self.config_dir / config_file
        
        if not config_path.exists():
            raise FileNotFoundError(f"配置文件不存在: {config_path}")
        
        # 检查缓存
        cache_key = str(config_path)
        if cache_key in self._config_cache:
            return self._config_cache[cache_key]
        
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                if config_file.endswith('.yaml') or config_file.endswith('.yml'):
                    config = yaml.safe_load(f)
                elif config_file.endswith('.json'):
                    config = json.load(f)
                else:
                    raise ValueError(f"不支持的配置文件格式: {config_file}")
            
            # 缓存配置
            self._config_cache[cache_key] = config
            self.logger.info(f"成功加载配置文件: {config_path}")
            return config
            
        except Exception as e:
            self.logger.error(f"加载配置文件失败: {e}")
            raise
    
    def parse_global_config(self, config: Dict[str, Any]) -> GlobalConfig:
        """解析全局配置"""
        global_config = config.get('global', {})
        
        return GlobalConfig(
            enabled=global_config.get('enabled', True),
            log_level=LogLevel(global_config.get('log_level', 'info')),
            log_file=global_config.get('log_file', '.git/hooks-controller.log'),
            fail_fast=global_config.get('fail_fast', True),
            max_parallel_tasks=global_config.get('max_parallel_tasks', 4)
        )
    
    def parse_hook_config(self, hook_name: str, config: Dict[str, Any]) -> HookConfig:
        """解析单个 Hook 配置"""
        hooks_config = config.get('hooks', {})
        hook_config = hooks_config.get(hook_name, {})
        
        tasks = []
        for task_data in hook_config.get('tasks', []):
            task = self._parse_task_config(task_data)
            tasks.append(task)
        
        return HookConfig(
            enabled=hook_config.get('enabled', True),
            description=hook_config.get('description', ''),
            tasks=tasks
        )
    
    def _parse_task_config(self, task_data: Dict[str, Any]) -> TaskConfig:
        """解析任务配置"""
        return TaskConfig(
            name=task_data.get('name', ''),
            type=TaskType(task_data.get('type', 'custom')),
            config=task_data.get('config', {}),
            conditions=task_data.get('conditions', []),
            parallel=task_data.get('parallel', False),
            timeout=task_data.get('timeout'),
            retry_count=task_data.get('retry_count', 0),
            enabled=task_data.get('enabled', True)
        )
    
    def parse_plugin_config(self, config: Dict[str, Any]) -> List[PluginConfig]:
        """解析插件配置"""
        plugins_config = config.get('plugins', {})
        plugins = []
        
        # 内置插件
        for plugin_data in plugins_config.get('builtin', []):
            plugin = PluginConfig(
                name=plugin_data.get('name', ''),
                path=plugin_data.get('path', ''),
                enabled=plugin_data.get('enabled', True),
                config=plugin_data.get('config', {})
            )
            plugins.append(plugin)
        
        # 自定义插件
        for plugin_data in plugins_config.get('custom', []):
            plugin = PluginConfig(
                name=plugin_data.get('name', ''),
                path=plugin_data.get('path', ''),
                enabled=plugin_data.get('enabled', False),
                config=plugin_data.get('config', {})
            )
            plugins.append(plugin)
        
        return plugins
    
    def get_hook_config(self, hook_name: str) -> Optional[HookConfig]:
        """获取指定 Hook 的配置"""
        try:
            config = self.load_config()
            return self.parse_hook_config(hook_name, config)
        except Exception as e:
            self.logger.error(f"获取 Hook 配置失败: {e}")
            return None
    
    def get_global_config(self) -> Optional[GlobalConfig]:
        """获取全局配置"""
        try:
            config = self.load_config()
            return self.parse_global_config(config)
        except Exception as e:
            self.logger.error(f"获取全局配置失败: {e}")
            return None
    
    def get_plugin_config(self) -> List[PluginConfig]:
        """获取插件配置"""
        try:
            config = self.load_config()
            return self.parse_plugin_config(config)
        except Exception as e:
            self.logger.error(f"获取插件配置失败: {e}")
            return []
    
    def validate_config(self, config: Dict[str, Any]) -> List[str]:
        """验证配置文件"""
        errors = []
        
        # 验证全局配置
        global_config = config.get('global', {})
        if 'log_level' in global_config:
            try:
                LogLevel(global_config['log_level'])
            except ValueError:
                errors.append(f"无效的日志级别: {global_config['log_level']}")
        
        # 验证 Hook 配置
        hooks_config = config.get('hooks', {})
        for hook_name, hook_config in hooks_config.items():
            if not isinstance(hook_config, dict):
                errors.append(f"Hook '{hook_name}' 配置格式错误")
                continue
            
            # 验证任务配置
            for i, task_data in enumerate(hook_config.get('tasks', [])):
                if not isinstance(task_data, dict):
                    errors.append(f"Hook '{hook_name}' 任务 {i} 配置格式错误")
                    continue
                
                if 'name' not in task_data:
                    errors.append(f"Hook '{hook_name}' 任务 {i} 缺少名称")
                
                if 'type' not in task_data:
                    errors.append(f"Hook '{hook_name}' 任务 {i} 缺少类型")
                else:
                    try:
                        TaskType(task_data['type'])
                    except ValueError:
                        errors.append(f"Hook '{hook_name}' 任务 {i} 无效的类型: {task_data['type']}")
        
        return errors
    
    def reload_config(self):
        """重新加载配置（清除缓存）"""
        self._config_cache.clear()
        self.logger.info("配置缓存已清除")


# 配置验证器
class ConfigValidator:
    """配置验证器"""
    
    @staticmethod
    def validate_file_path(path: str) -> bool:
        """验证文件路径"""
        return os.path.exists(path)
    
    @staticmethod
    def validate_plugin_path(plugin_path: str) -> bool:
        """验证插件路径"""
        return os.path.exists(plugin_path) and plugin_path.endswith('.py')
    
    @staticmethod
    def validate_regex_pattern(pattern: str) -> bool:
        """验证正则表达式"""
        try:
            import re
            re.compile(pattern)
            return True
        except re.error:
            return False


if __name__ == "__main__":
    # 测试配置解析器
    parser = ConfigParser()
    
    try:
        config = parser.load_config()
        print("配置文件加载成功")
        
        # 验证配置
        errors = parser.validate_config(config)
        if errors:
            print("配置验证错误:")
            for error in errors:
                print(f"  - {error}")
        else:
            print("配置验证通过")
        
        # 测试获取配置
        global_config = parser.get_global_config()
        if global_config:
            print(f"全局配置: {global_config}")
        
        hook_config = parser.get_hook_config('pre-commit')
        if hook_config:
            print(f"pre-commit 配置: {hook_config}")
        
    except Exception as e:
        print(f"测试失败: {e}")
